"""
股票分析工具函数
提供技术指标计算、基本面分析等功能
"""
import pandas as pd
import numpy as np
from typing import Dict, List, Any, Optional, Union
from loguru import logger

from database.data_collector import DataCollector

def calculate_technical_indicators(stock_code: str, timeframe: str = "daily") -> Dict[str, Any]:
    """
    计算技术指标
    
    参数:
        stock_code: 股票代码
        timeframe: 时间周期
        
    返回:
        技术指标计算结果
    """
    logger.info(f"计算股票 {stock_code} 技术指标")
    
    try:
        # 获取历史数据
        from config.settings import BACKTEST_START_DATE
        data_collector = DataCollector()
        start_date = BACKTEST_START_DATE.replace("-", "")  # 转换格式从YYYY-MM-DD到YYYYMMDD
        hist_data = data_collector.get_daily_data(stock_code, start_date)
        
        if hist_data.empty:
            logger.warning(f"无法获取股票 {stock_code} 的历史数据")
            return {"error": "无历史数据"}
        
        # 定义列名映射关系(中文->英文)
        columns_mapping = {
            '开盘': ['open', 'Open', 'OPEN'],
            '最高': ['high', 'High', 'HIGH'],
            '最低': ['low', 'Low', 'LOW'],
            '收盘': ['close', 'Close', 'CLOSE'],
            '成交量': ['volume', 'Volume', 'VOLUME']
        }
        
        # 统一列名为中文
        for cn_col, en_cols in columns_mapping.items():
            for en_col in en_cols:
                if en_col in hist_data.columns and cn_col not in hist_data.columns:
                    hist_data[cn_col] = hist_data[en_col]
                    break
        
        # 检查必要列是否存在
        required_columns = ['开盘', '最高', '最低', '收盘']
        missing_columns = [col for col in required_columns if col not in hist_data.columns]
        
        if missing_columns:
            logger.warning(f"股票 {stock_code} 的数据缺少必要列: {missing_columns}")
            logger.debug(f"可用列: {hist_data.columns.tolist()}")
            
            # 尝试从akshare重新获取数据
            try:
                hist_data = data_collector.get_daily_data(stock_code, start_date)
                
                # 再次统一列名
                for cn_col, en_cols in columns_mapping.items():
                    for en_col in en_cols:
                        if en_col in hist_data.columns and cn_col not in hist_data.columns:
                            hist_data[cn_col] = hist_data[en_col]
                            break
                
                # 再次检查列名
                missing_columns = [col for col in required_columns if col not in hist_data.columns]
                if missing_columns:
                    logger.error(f"重试后仍缺少列: {missing_columns}")
                    return {"error": f"数据缺少必要列: {missing_columns}"}
                    
            except Exception as e:
                logger.error(f"重新获取数据失败: {e}")
                return {"error": "数据获取失败"}
        
        # 确保日期列是datetime类型
        if '日期' in hist_data.columns:
            try:
                hist_data['日期'] = pd.to_datetime(hist_data['日期'])
            except Exception as e:
                logger.warning(f"日期列转换失败: {e}，使用原始格式")
        
        # 价格数据
        prices = hist_data.set_index('日期')
        if not isinstance(prices.index, pd.DatetimeIndex):
            logger.warning("日期列转换后仍不是datetime类型，使用默认日期")
            prices.index = pd.date_range(end=pd.Timestamp.now(), periods=len(prices), freq='D')
        
        # 确保所有必要的列都存在
        if '收盘' not in prices.columns:
            logger.error(f"股票 {stock_code} 的数据缺少'收盘'列")
            return {"error": "数据缺少'收盘'列"}
        
        close_prices = prices['收盘'].astype(float)
        
        # 检查并获取其他价格数据
        if '开盘' in prices.columns:
            open_prices = prices['开盘'].astype(float)
        else:
            logger.error(f"股票 {stock_code} 的数据缺少'开盘'列")
            return {"error": "数据缺少'开盘'列"}
            
        if '最高' in prices.columns:
            high_prices = prices['最高'].astype(float)
        else:
            logger.error(f"股票 {stock_code} 的数据缺少'最高'列")
            return {"error": "数据缺少'最高'列"}
            
        if '最低' in prices.columns:
            low_prices = prices['最低'].astype(float)
        else:
            logger.error(f"股票 {stock_code} 的数据缺少'最低'列")
            return {"error": "数据缺少'最低'列"}
            
        if '成交量' in prices.columns:
            volumes = prices['成交量'].astype(float)
        else:
            logger.warning(f"股票 {stock_code} 的数据缺少'成交量'列，使用默认值")
            volumes = pd.Series(0, index=prices.index)
        
        # 计算移动平均线
        ma5 = close_prices.rolling(window=5).mean().iloc[-1]
        ma10 = close_prices.rolling(window=10).mean().iloc[-1]
        ma20 = close_prices.rolling(window=20).mean().iloc[-1]
        ma30 = close_prices.rolling(window=30).mean().iloc[-1]
        ma60 = close_prices.rolling(window=60).mean().iloc[-1]
        
        # 计算MACD
        ema12 = close_prices.ewm(span=12, adjust=False).mean()
        ema26 = close_prices.ewm(span=26, adjust=False).mean()
        macd = ema12 - ema26
        signal = macd.ewm(span=9, adjust=False).mean()
        histogram = macd - signal
        
        # 计算RSI
        delta = close_prices.diff()
        gain = delta.clip(lower=0)
        loss = -delta.clip(upper=0)
        avg_gain = gain.rolling(window=14).mean()
        avg_loss = loss.rolling(window=14).mean()
        rs = avg_gain / avg_loss
        rsi = 100 - (100 / (1 + rs))
        
        # 计算布林带
        sma20 = close_prices.rolling(window=20).mean()
        std20 = close_prices.rolling(window=20).std()
        upper_band = sma20 + (std20 * 2)
        lower_band = sma20 - (std20 * 2)
        
        # 计算KDJ
        low_min = low_prices.rolling(window=9).min()
        high_max = high_prices.rolling(window=9).max()
        rsv = 100 * ((close_prices - low_min) / (high_max - low_min))
        k = rsv.ewm(alpha=1/3, adjust=False).mean()
        d = k.ewm(alpha=1/3, adjust=False).mean()
        j = 3 * k - 2 * d
        
        # 计算成交量变化率
        volume_change = volumes.pct_change().iloc[-1] * 100
        
        # 计算价格变化率
        price_change_1d = close_prices.pct_change(periods=1).iloc[-1] * 100
        price_change_5d = close_prices.pct_change(periods=5).iloc[-1] * 100
        price_change_20d = close_prices.pct_change(periods=20).iloc[-1] * 100
        
        # 计算相对强度（与大盘对比）
        try:
            index_data = data_collector.get_index_data("000001", start_date)  # 上证指数
            index_close = index_data.set_index('date')['close'].astype(float)
            stock_rs = (close_prices.pct_change(periods=20).iloc[-1] / 
                       index_close.pct_change(periods=20).iloc[-1])
        except:
            stock_rs = None
        
        # 最新价格
        latest_close = close_prices.iloc[-1]
        latest_open = open_prices.iloc[-1]
        latest_high = high_prices.iloc[-1]
        latest_low = low_prices.iloc[-1]
        latest_volume = volumes.iloc[-1]
        
        return {
            "latest_price": {
                "open": latest_open,
                "high": latest_high,
                "low": latest_low,
                "close": latest_close,
                "volume": latest_volume
            },
            "price_change": {
                "daily": price_change_1d,
                "weekly": price_change_5d,
                "monthly": price_change_20d
            },
            "moving_averages": {
                "ma5": ma5,
                "ma10": ma10,
                "ma20": ma20,
                "ma30": ma30,
                "ma60": ma60,
                "price_vs_ma5": latest_close / ma5 - 1,
                "price_vs_ma10": latest_close / ma10 - 1,
                "price_vs_ma20": latest_close / ma20 - 1,
                "price_vs_ma60": latest_close / ma60 - 1
            },
            "macd": {
                "macd": macd.iloc[-1],
                "signal": signal.iloc[-1],
                "histogram": histogram.iloc[-1]
            },
            "rsi": {
                "rsi14": rsi.iloc[-1]
            },
            "bollinger_bands": {
                "middle": sma20.iloc[-1],
                "upper": upper_band.iloc[-1],
                "lower": lower_band.iloc[-1],
                "width": (upper_band.iloc[-1] - lower_band.iloc[-1]) / sma20.iloc[-1]
            },
            "kdj": {
                "k": k.iloc[-1],
                "d": d.iloc[-1],
                "j": j.iloc[-1]
            },
            "volume": {
                "latest": latest_volume,
                "change": volume_change
            },
            "relative_strength": stock_rs,
            "trend_analysis": analyze_trend(close_prices, ma5, ma20, rsi.iloc[-1])
        }
    
    except Exception as e:
        logger.error(f"计算技术指标失败: {e}")
        return {
            "pe_ttm": None,
            "pe_forward": None,
            "pb": None,
            "ps_ttm": None,
            "ev_ebitda": None,
            "dividend_yield": None,
            "peg": None,
            "fair_value": None,
            "upside_potential": None
        }


def analyze_trend(prices: pd.Series, ma5: float, ma20: float, rsi: float) -> Dict[str, Any]:
    """
    分析价格趋势
    
    参数:
        prices: 价格序列
        ma5: 5日移动平均
        ma20: 20日移动平均
        rsi: 相对强弱指标
        
    返回:
        趋势分析结果
    """
    latest_price = prices.iloc[-1]
    
    # 判断短期趋势
    short_term = "上升" if latest_price > ma5 else "下降"
    
    # 判断中期趋势
    medium_term = "上升" if ma5 > ma20 else "下降"
    
    # 根据RSI判断超买超卖
    oversold = rsi < 30
    overbought = rsi > 70
    
    # 判断价格形态
    recent_prices = prices.iloc[-20:]
    max_price = recent_prices.max()
    min_price = recent_prices.min()
    
    # 检查是否处于盘整
    consolidating = (max_price - min_price) / min_price < 0.05
    
    # 检查是否处于突破
    breaking_out = latest_price > max_price * 0.98
    breaking_down = latest_price < min_price * 1.02
    
    # 综合趋势评估
    if short_term == "上升" and medium_term == "上升":
        overall_trend = "强势上涨"
    elif short_term == "下降" and medium_term == "下降":
        overall_trend = "强势下跌"
    elif short_term == "上升" and medium_term == "下降":
        overall_trend = "反弹"
    else:
        overall_trend = "回调"
    
    if consolidating:
        overall_trend = "盘整"
    
    if breaking_out:
        overall_trend = "突破"
    elif breaking_down:
        overall_trend = "跌破"
    
    return {
        "short_term": short_term,
        "medium_term": medium_term,
        "overall_trend": overall_trend,
        "oversold": oversold,
        "overbought": overbought,
        "consolidating": consolidating,
        "breaking_out": breaking_out,
        "breaking_down": breaking_down
    }


def analyze_financial_data(stock_code: str) -> Dict[str, Any]:
    """
    分析财务数据
    
    参数:
        stock_code: 股票代码
        
    返回:
        财务分析结果，包含:
        - profitability: 盈利能力指标
        - growth: 成长性指标
        - valuation: 估值指标
        - solvency: 偿债能力指标
        - efficiency: 运营效率指标
        - cash_flow: 现金流指标
    """
    logger.info(f"分析股票 {stock_code} 财务数据")
    
    try:
        # 从数据源获取财务数据
        data_collector = DataCollector()
        financials = data_collector.get_financial_data(stock_code)
        
        if financials.empty:
            logger.warning(f"无法获取股票 {stock_code} 的财务数据")
            return {"error": "无财务数据"}
            
        # 计算各项财务指标
        latest_report = financials.iloc[-1]
        
        # 盈利能力指标
        profitability = {
            "gross_margin": latest_report['gross_profit'] / latest_report['revenue'],
            "operating_margin": latest_report['operating_profit'] / latest_report['revenue'],
            "net_margin": latest_report['net_profit'] / latest_report['revenue'],
            "roe": latest_report['net_profit'] / latest_report['equity'],
            "roa": latest_report['net_profit'] / latest_report['total_assets']
        }
        
        # 成长性指标(与上期比较)
        if len(financials) > 1:
            prev_report = financials.iloc[-2]
            growth = {
                "revenue_growth": (latest_report['revenue'] - prev_report['revenue']) / prev_report['revenue'],
                "profit_growth": (latest_report['net_profit'] - prev_report['net_profit']) / prev_report['net_profit'],
                "asset_growth": (latest_report['total_assets'] - prev_report['total_assets']) / prev_report['total_assets']
            }
        else:
            growth = {
                "revenue_growth": None,
                "profit_growth": None,
                "asset_growth": None
            }
            
        # 估值指标(需要市场价格数据)
        price_data = data_collector.get_daily_data(stock_code)
        if not price_data.empty:
            latest_price = price_data['close'].iloc[-1]
            valuation = {
                "pe_ratio": latest_price / latest_report['eps'],
                "pb_ratio": latest_price / (latest_report['equity'] / latest_report['shares']),
                "ps_ratio": latest_price / (latest_report['revenue'] / latest_report['shares']),
                "dividend_yield": latest_report['dividend_per_share'] / latest_price
            }
        else:
            valuation = {
                "pe_ratio": None,
                "pb_ratio": None,
                "ps_ratio": None,
                "dividend_yield": None
            }
            
        # 偿债能力指标
        solvency = {
            "debt_to_equity": latest_report['total_liabilities'] / latest_report['equity'],
            "current_ratio": latest_report['current_assets'] / latest_report['current_liabilities'],
            "quick_ratio": (latest_report['current_assets'] - latest_report['inventory']) / latest_report['current_liabilities']
        }
        
        # 运营效率指标
        efficiency = {
            "asset_turnover": latest_report['revenue'] / latest_report['total_assets'],
            "inventory_turnover": latest_report['cogs'] / latest_report['inventory'],
            "receivable_turnover": latest_report['revenue'] / latest_report['receivables']
        }
        
        # 现金流指标
        cash_flow = {
            "operating_cash_flow": latest_report['operating_cash_flow'],
            "free_cash_flow": latest_report['operating_cash_flow'] - latest_report['capital_expenditure'],
            "cash_flow_to_debt": latest_report['operating_cash_flow'] / latest_report['total_liabilities']
        }
        
        return {
            "profitability": profitability,
            "growth": growth,
            "valuation": valuation,
            "solvency": solvency,
            "efficiency": efficiency,
            "cash_flow": cash_flow
        }
    
    except Exception as e:
        logger.error(f"分析财务数据失败: {e}")
        logger.error(f"计算估值指标失败: {e}")
        return {
            "pe_ttm": None,
            "pe_forward": None,
            "pb": None,
            "ps_ttm": None,
            "ev_ebitda": None,
            "dividend_yield": None,
            "peg": None,
            "fair_value": None,
            "upside_potential": None
        }


def calculate_valuation_metrics(stock_code: str) -> Dict[str, Optional[float]]:
    """
    计算估值指标
    
    参数:
        stock_code: 股票代码
        
    返回:
        估值指标计算结果，包含:
        - pe_ttm: 市盈率(TTM)
        - pe_forward: 前瞻市盈率
        - pb: 市净率
        - ps_ttm: 市销率(TTM)
        - ev_ebitda: 企业价值倍数
        - dividend_yield: 股息率
        - peg: 市盈增长比率
        - fair_value: 公允价值估算
        - upside_potential: 上涨潜力
    """
    logger.info(f"计算股票 {stock_code} 估值指标")
    
    try:
        # 获取财务数据和市场价格
        data_collector = DataCollector()
        financials = data_collector.get_financial_data(stock_code)
        price_data = data_collector.get_daily_data(stock_code)
        
        if financials.empty or price_data.empty:
            logger.warning(f"无法获取股票 {stock_code} 的财务或价格数据")
            return {
                "pe_ttm": None,
                "pe_forward": None,
                "pb": None,
                "ps_ttm": None,
                "ev_ebitda": None,
                "dividend_yield": None,
                "peg": None,
                "fair_value": None,
                "upside_potential": None
            }
            
        latest_fin = financials.iloc[-1]
        latest_price = price_data['close'].iloc[-1]
        
        # 计算基础估值指标
        pe_ttm = latest_price / latest_fin['eps']
        pb = latest_price / (latest_fin['equity'] / latest_fin['shares'])
        ps_ttm = latest_price / (latest_fin['revenue'] / latest_fin['shares'])
        dividend_yield = latest_fin['dividend_per_share'] / latest_price
        
        # 计算前瞻市盈率(基于分析师预测)
        analyst_estimates = data_collector.get_analyst_estimates(stock_code)
        if not analyst_estimates.empty:
            forward_eps = analyst_estimates['forward_eps'].iloc[-1]
            pe_forward = latest_price / forward_eps
        else:
            pe_forward = None
            
        # 计算EV/EBITDA
        enterprise_value = latest_price * latest_fin['shares'] + latest_fin['total_debt'] - latest_fin['cash']
        ev_ebitda = enterprise_value / latest_fin['ebitda']
        
        # 计算PEG(需要盈利增长率)
        if len(financials) > 4:  # 至少有4个季度数据
            eps_growth = (latest_fin['eps'] - financials.iloc[-4]['eps']) / financials.iloc[-4]['eps']
            peg = pe_ttm / (eps_growth * 100) if eps_growth else None
        else:
            peg = None
            
        # 计算公允价值(DCF模型简化版)
        if latest_fin['free_cash_flow'] > 0:
            # 假设永续增长率为3%，折现率为10%
            fair_value = latest_fin['free_cash_flow'] * (1 + 0.03) / (0.10 - 0.03) / latest_fin['shares']
            upside_potential = (fair_value - latest_price) / latest_price
        else:
            fair_value = None
            upside_potential = None
            
        return {
            "pe_ttm": float(pe_ttm) if pd.notnull(pe_ttm) else None,
            "pe_forward": float(pe_forward) if pe_forward and pd.notnull(pe_forward) else None,
            "pb": float(pb) if pd.notnull(pb) else None,
            "ps_ttm": float(ps_ttm) if pd.notnull(ps_ttm) else None,
            "ev_ebitda": float(ev_ebitda) if pd.notnull(ev_ebitda) else None,
            "dividend_yield": float(dividend_yield) if pd.notnull(dividend_yield) else None,
            "peg": float(peg) if peg and pd.notnull(peg) else None,
            "fair_value": float(fair_value) if fair_value and pd.notnull(fair_value) else None,
            "upside_potential": float(upside_potential) if upside_potential and pd.notnull(upside_potential) else None
        }
    
    except Exception as e:
        logger.error(f"计算估值指标失败: {e}")
        logger.error(f"分析财务数据失败: {e}")
        logger.error(f"计算估值指标失败: {e}")
        return {
            "pe_ttm": None,
            "pe_forward": None,
            "pb": None,
            "ps_ttm": None,
            "ev_ebitda": None,
            "dividend_yield": None,
            "peg": None,
            "fair_value": None,
            "upside_potential": None
        }